home *** CD-ROM | disk | FTP | other *** search
/ Young Minds / Young Minds Interactive CD-ROM.ISO / kriegspi / input.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-06-30  |  12.8 KB  |  516 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Header: input.c,v 1.3 87/05/19 18:46:55 schoch Exp $";
  3. #endif
  4.  
  5. #include "externs.h"
  6. #include <ctype.h>
  7. #include <strings.h>
  8. #include <sys/time.h>
  9.  
  10. char instr [128];
  11. static int opponent;
  12.  
  13. entermove (pstart, pend, color, pawntries)
  14.     int *pstart, *pend, color, pawntries;
  15. {
  16.     int i, readfds;
  17.     int counter = 0;
  18.     struct timeval timeout;
  19.     char c;
  20.     char *cp;
  21.  
  22.     timeout.tv_sec = (long int) 1;
  23.     timeout.tv_usec = (long int) 0;
  24.     wclear (win [OPPONENT]);
  25.     while (TRUE) {
  26.         drawok [color] = FALSE;
  27.         if (color == ourcolor) {
  28.             printf ("\007");    /* ring bell */
  29.             if (drawok [1 - color]) {
  30.                 waddstr (win [MESSAGE], "draw offered");
  31.                 wclear (win [MESSAGE]);
  32.             }
  33.             wclear (win [INPUT]);
  34.             waddstr (win [INPUT], ": ");
  35.             waddstr (win [PROMPT], "your move");
  36.             i = 0;
  37.             while (TRUE) {
  38.                 move (win [INPUT]->_cury + win [INPUT]->_begy,
  39.                       win [INPUT]->_curx + win [INPUT]->_begx);
  40.                 refresh ();
  41.                 instr [i] = getchar ();
  42.                 if (instr [i] == '\n'
  43.                 ||  instr [i] == '\r')
  44.                     break;
  45.                 else if (instr [i] == '\f') {    /* ^L */
  46.                     redraw();
  47.                     continue;
  48.                 } else if (instr [i] == '\b'    /* ^H */
  49.                 || instr [i] == '\177') {    /* delete */
  50.                     if (i > 0) {
  51.                         --i;
  52.                         wmove( win [INPUT],
  53.                                win [INPUT]->_cury,
  54.                                win [INPUT]->_curx - 1);
  55.                         wdelch (win [INPUT]);
  56.                     }
  57.                     continue;
  58.                 } else if (instr [i] == '\030'    /* ^X */
  59.                 || instr [i] == '\025') {    /* ^U */
  60.                     wclear (win [INPUT]);
  61.                     waddstr (win [INPUT], ": ");
  62.                     i = 0;
  63.                     continue;
  64.                 } else if (isupper (instr [i]))
  65.                     tolower (instr [i]);
  66.                 wclear (win [LEGAL]);
  67.                 if (isprint (instr [i]))
  68.                     waddch (win [INPUT], instr [i++]);
  69.             }
  70.             instr [i] = '\000';
  71.             wclear (win [INPUT]);
  72.             opponent = FALSE;
  73.         } else {
  74.             i = 0;
  75.             wclear (win [MESSAGE]);
  76.             waddstr (win [MESSAGE],
  77.                  "waiting for\nopponent's\nmove");
  78.             refresh ();
  79.             while (TRUE) {
  80.                 readfds = 1 + (1 << fileno(inp));
  81.                 while (select (fileno(inp)+1, &readfds, (int *)
  82.                            NULL, (int *) NULL,
  83.                            &timeout) < 0)
  84.                     if (errno != EINTR)
  85.                         error ("select in entermove");
  86.                 if (! (readfds & (1 << fileno(inp)))) {
  87.                     wclear (win [CLOCK]);
  88.                     if (counter++ % 2 == 1)
  89.                         waddch (win [CLOCK],'/');
  90.                     else
  91.                         waddch (win [CLOCK],'\\');
  92.                     move (win [CLOCK]->_begy,
  93.                           win [CLOCK]->_begx);
  94.                     refresh();
  95.                     if (readfds & 1) {
  96.                         c = getch();
  97.                         if (c == '\f'    /* ^L */)
  98.                             redraw();
  99.                     }
  100.                 }
  101.                 else
  102.                     break;
  103.                 wclear (win [LEGAL]);
  104.             }
  105.             wclear (win [LEGAL]);
  106.             if (fgets(instr, sizeof instr, inp) == NULL) {
  107.                 if (ferror(inp))
  108.                     error("read in entermove");
  109.                 dead = TRUE;
  110.                 if (state == PLAYING)
  111.                     state = OVER;
  112.             } else {
  113.                 if (cp = index(instr, '\n'))
  114.                     *cp = '\0';
  115.                 if (cp = index(instr, '\r'))
  116.                     *cp = '\0';
  117.             }
  118.             opponent = TRUE;
  119.         }
  120.         wclear (win [PROMPT]);
  121.         *pstart = *pend = 0;
  122.         if (!strcmp (instr, "draw")) {
  123.             drawok [color] = TRUE;
  124.             if (!opponent)
  125.                 fputs("draw\r\n", out);
  126.             break;
  127.         } else if (!strcmp (instr, "resign")) {
  128.             resign = TRUE;
  129.             state = OVER;
  130.             if (!opponent)
  131.                 fputs("resign\r\n", out);
  132.             break;
  133.         } else if (drawok [1 - color]) {
  134.             if (!strcmp (instr, "yes")) {
  135.                 drawok [color] = TRUE;
  136.                 state = OVER;
  137.                 if (!opponent)
  138.                     fputs("yes\r\n", out);
  139.                 break;
  140.             } else if (!strcmp (instr, "no")) {
  141.                 if (ourcolor != color)
  142.                     waddstr (win[MESSAGE], "draw refused");
  143.                 if (!opponent)
  144.                     fputs("no\r\n", out);
  145.                 break;
  146.             } else {
  147.                 wclear (win [MESSAGE]);
  148.                 waddstr (win [MESSAGE],
  149.                      "draw offered\ntype yes or no\n");
  150.             }
  151.         } else if (!strcmp (instr, "o-o-o")
  152.         && kingloc [color] % 10 == 5) {
  153.             *pstart = kingloc [color];
  154.             *pend = kingloc [color] - 2;
  155.             if (!opponent)
  156.                 send_move(*pstart, *pend);
  157.             break;
  158.         } else if (!strcmp (instr, "o-o")
  159.         && kingloc [color] % 10 == 5) {
  160.             *pstart = kingloc [color];
  161.             *pend = kingloc [color] + 2;
  162.             if (!opponent)
  163.                 send_move(*pstart, *pend);
  164.             break;
  165.         } else if ((!strncmp (instr, "help", 4) || !strcmp (instr,""))
  166.         && color == ourcolor) {
  167.             wclear (win [MESSAGE]);
  168.             waddstr (win [MESSAGE],
  169.                  "eg. qe4, p-k4\npxkb3, o-o-o\n");
  170.             waddstr (win [MESSAGE],
  171.                  "draw, resign\nsay you'll lose");
  172.         } else if (!strncmp (instr, "say", 3)) {
  173.             if (opponent) {
  174.                 wclear (win [OPPONENT]);
  175.                 waddstr (win [OPPONENT], "message:\n");
  176.                 waddstr (win [OPPONENT], instr + 3);
  177.                 waddch (win [OPPONENT], '\n');
  178.             } else
  179.                 fprintf(out, "say %s\r\n", instr+3);
  180.         } else if ((!option [ANNOUNCEPAWNS])
  181.         && (!strcmp (instr, "any")))
  182.             if (pawntries)
  183.                 waddstr (win [PAWNTRIES], "pawntries\r");
  184.             else
  185.                 waddstr (win [PAWNTRIES], "no pawntries\r");
  186.         else {
  187.             if ((i = parse_algebraic_move(pstart,pend,color))
  188.                 == NOWAY)
  189.                 i = parse_descriptive_move (pstart,pend,color);
  190.             if (i == TRUE) {
  191.                 if (!opponent)
  192.                     send_move(*pstart, *pend);
  193.                 break;
  194.             } else
  195.                 illegal (i, color);
  196.         }
  197.     }
  198. }
  199.  
  200. #define boardpos(col, row)  ((9 - (row)) * 10 + (col))
  201. #define RIGHT_SIDE 2
  202. #define RIGHT_FILE 1
  203.  
  204. /* parse an algebraic move (e2-e4), and return TRUE for non error */
  205. /* opponent is true if this move is from the opponent.  Moves set across
  206.  * the network are standardized whether reverse is set or not. */
  207. parse_algebraic_move (pstart, pend, color)
  208.     int *pstart, *pend, color;
  209. {
  210.     int foundpiece = FALSE, i, j, piece, spot;
  211.     LIST piecemoves (), lmember ();
  212.  
  213.     if (strlen (instr) == 5)
  214.         if (instr [0] >= 'a' && instr [0] <= 'h'
  215.         &&  instr [1] >= '1' && instr [1] <= '8'
  216.         &&  instr [3] >= 'a' && instr [3] <= 'h'
  217.         &&  instr [4] >= '1' && instr [4] <= '8') {
  218.             *pstart = boardpos (instr[0]-'a'+1, instr[1]-'0');
  219.             *pend   = boardpos (instr[3]-'a'+1, instr[4]-'0');
  220.             if (reverse && !opponent) {
  221.                 *pstart = 99 - *pstart;
  222.                 *pend   = 99 - *pend;
  223.             }
  224.             return TRUE;
  225.         } else
  226.  
  227.             return NOWAY;
  228.     else if (strlen (instr) == 4)
  229.         if (instr [0] >= 'a' && instr [0] <= 'h'
  230.         &&  instr [1] >= '1' && instr [1] <= '8'
  231.         &&  instr [2] >= 'a' && instr [2] <= 'h'
  232.         &&  instr [3] >= '1' && instr [3] <= '8') {
  233.             *pstart = boardpos (instr[0]-'a'+1, instr[1]-'0');
  234.             *pend   = boardpos (instr[2]-'a'+1, instr[3]-'0');
  235.             if (reverse && !opponent) {
  236.                 *pstart = 99 - *pstart;
  237.                 *pend   = 99 - *pend;
  238.             }
  239.             return TRUE;
  240.         } else
  241.  
  242.             return NOWAY;
  243.     else if (strlen (instr) == 2) {
  244.         if (instr [0] < 'a' || instr [0] > 'h')
  245.             return NOWAY;
  246.         else if (instr [1] >= 'a' && instr [1] <= 'h') {
  247.             /* pawn take */
  248.             for (i = 2; i <= 7 ; i++) {
  249.                 spot = boardpos (instr[0]-'a'+1, i);
  250.                 if (reverse && !opponent)
  251.                     spot = 99 - spot;
  252.                 if (whose [spot] == color
  253.                 && occupant [spot] == PAWN)
  254.                     if (foundpiece)
  255.                         return AMBIGUOUS;
  256.                     else
  257.                         foundpiece = spot;
  258.             }
  259.             if (foundpiece) {
  260.                 *pstart = foundpiece;
  261.                 if (reverse && !opponent)
  262.                     *pend = boardpos ('i'-instr[1],
  263.                               9 - foundpiece / 10)
  264.                         + pawndir [color];
  265.                 else
  266.                     *pend = boardpos (instr[1]-'a'+1,
  267.                               9 - foundpiece / 10)
  268.                         + pawndir [color];
  269.                 return TRUE;
  270.             } else
  271.                 return NOWAY;
  272.         } else if (instr [1] >= '1' && instr [1] <= '8') {
  273.             /* pawn move */
  274.             *pend = boardpos (instr[0]-'a'+1, instr[1]-'0');
  275.             if (reverse && !opponent)
  276.                 *pend = 99 - *pend;
  277.             if (((ourcolor == BLACK) && (*pend <= 28))
  278.             ||  ((ourcolor == WHITE) && (*pend >= 71)))
  279.                 return NOWAY;
  280.             if ((whose [*pstart= *pend - pawndir [color]] == color
  281.                  && occupant [*pstart] == PAWN)
  282.             || (whose [*pstart= *pstart - pawndir [color]] == color
  283.                 && occupant [*pstart] == PAWN))
  284.                 return TRUE;
  285.             else
  286.                 return NOWAY;
  287.         } else
  288.             return NOWAY;
  289.     } else if (strlen (instr) == 3) {    /* eg. nc6 */
  290.         if ((piece = piecetype(instr [0])) == ILLEGAL_PIECE)
  291.             return NOWAY;
  292.         if (instr [1] < 'a' || instr [1] > 'h'
  293.         || instr [2] < '0' || instr [2] >'h')
  294.             return NOWAY;
  295.         *pend = boardpos (instr [1] - 'a' + 1, instr [2] - '0');
  296.         if (reverse && !opponent)
  297.             *pend = 99 - *pend;
  298.         for (i = 1; i <= 8; i++) {
  299.             for (j = 1; j <= 8; j++) {
  300.                 *pstart = boardpos (i, j);
  301.                 if (whose [*pstart] != color
  302.                 || occupant [*pstart] != piece
  303.                 || !lmember (*pend, piecemoves(*pstart,TRUE)))
  304.                     continue;
  305.                 if (foundpiece)
  306.                     return AMBIGUOUS;
  307.                 foundpiece = *pstart;
  308.             }
  309.         }
  310.         if (*pstart = foundpiece)
  311.             return TRUE;
  312.         else
  313.             return NOWAY;
  314.     }
  315.     return NOWAY;   /* shoud never be reached */
  316. }
  317.  
  318. /* parse a descriptive move (n-kb3), return TRUE for non error */
  319. parse_descriptive_move (pstart, pend, color)
  320.     int *pstart, *pend, color;
  321. {
  322.     char *sfrom, *sto, *alloca(), *index(), *afterslash;
  323.     int nlegalbyfile = 0, nlegalbyside = 0, fromlegal = 0, frombyfile
  324.         , frombyside, pawntake = FALSE, piece;
  325.     LIST tryto, targets, piecemoves ();
  326.     int i, j, spot, tobyfile, tobyside;
  327.     struct {
  328.         int row;
  329.         int col;
  330.         int goodness;
  331.     } xfrom[100];
  332.  
  333.     /* sfrom is from string, sto is to string */
  334.     sfrom = alloca (strlen (instr) + 1);
  335.     strcpy(sfrom, instr);
  336.     if ((sto = index (sfrom, '-')) == NULL)
  337.         if ((sto = index (sfrom, 'x')) != NULL)
  338.             pawntake = TRUE;
  339.         else
  340.             return NOWAY;
  341.     *sto++ = '\0';
  342.     if ((afterslash = index (sfrom, '/')) != NULL)
  343.         *afterslash++ = '\0';
  344.     if ((piece = piecetype(sfrom [strlen (sfrom) - 1])) == ILLEGAL_PIECE)
  345.         return NOWAY;
  346.     pawntake = pawntake && piece == PAWN;
  347.     sfrom [strlen (sfrom) - 1] = '\0';
  348.  
  349.     /* build a list of legal from moves */
  350.     for (i = 1; i <= 8; i++) {
  351.         for (j = 1; j <= 8; j++) {
  352.             spot = (9 - i) * 10 + j;
  353.             if (whose [spot] != color)
  354.                 continue;
  355.             if (occupant [spot] != piece)
  356.                 continue;
  357.             xfrom [fromlegal].goodness = RIGHT_FILE;
  358.             if (afterslash) {
  359.                 switch (xfrom [fromlegal].goodness
  360.                     = matchpos(afterslash, spot, color)) {
  361.                 case FALSE:
  362.                     continue;
  363.                 case ILLEGAL:
  364.                     return NOWAY;
  365.                 case RIGHT_SIDE:
  366.                 case RIGHT_FILE:
  367.                     break;
  368.                 }
  369.             }
  370.             if (*sfrom) {
  371.                 switch (xfrom [fromlegal].goodness
  372.                     = matchpos(sfrom, spot, color)) {
  373.                 case FALSE:
  374.                     continue;
  375.                 case ILLEGAL:
  376.                     return NOWAY;
  377.                 case RIGHT_SIDE:
  378.                 case RIGHT_FILE:
  379.                     break;
  380.                 }
  381.             }
  382.             xfrom[fromlegal].row = i;
  383.             xfrom[fromlegal].col = j;
  384.             fromlegal++;
  385.         }
  386.     }
  387.  
  388.     /* find all the consistent 'to' moves for those 'from' moves */
  389.     for (i = 0; i < fromlegal; i++) {
  390.         spot = (9 - xfrom [i].row) * 10 + xfrom [i].col;
  391.         targets = piecemoves (spot, TRUE);
  392.         for (tryto = targets; tryto != NULL; tryto = tryto->n) {
  393.             switch (matchpos(sto, tryto->i, color)) {
  394.             case RIGHT_FILE:
  395.                 if (xfrom [i].goodness == RIGHT_FILE) {
  396.                     if (piece == PAWN
  397.                     && pawntake == ((tryto->i % 10)
  398.                             == (xfrom[i].col)))
  399.                         continue;
  400.                     frombyfile = i;
  401.                     tobyfile = tryto -> i;
  402.                     nlegalbyfile++;
  403.                 }
  404.                 /* fall through */
  405.             case RIGHT_SIDE:
  406.                 if (piece == PAWN
  407.                 && pawntake
  408.                     == ((tryto->i % 10) == (xfrom[i].col)))
  409.                     continue;
  410.                 frombyside = i;
  411.                 tobyside = tryto -> i;
  412.                 nlegalbyside++;
  413.                 break;
  414.             case FALSE:
  415.                 continue;
  416.             case ILLEGAL:
  417.                 return NOWAY;
  418.             }
  419.         }
  420.     }
  421.  
  422.     /* complain if there are too many or if there are none */
  423.     if (nlegalbyside != 1 && nlegalbyfile != 1) {
  424.         if (nlegalbyside > 1)
  425.             return AMBIGUOUS;
  426.         else
  427.             return NOWAY;
  428.     }
  429.  
  430.     if (nlegalbyside == 1) {
  431.         /* frombyside and tobyside now define the unique legal move */
  432.         *pstart = (9 - xfrom[frombyside].row) * 10
  433.             + xfrom[frombyside].col;
  434.         *pend = tobyside;
  435.     } else if (nlegalbyfile == 1) {
  436.         /* frombyfile and tobyfile now define the unique legal move */
  437.         *pstart = (9 - xfrom[frombyfile].row) * 10
  438.             + xfrom[frombyfile].col;
  439.         *pend = tobyfile;
  440.     }
  441.     return TRUE;
  442. }
  443.  
  444. /* matchpos -- tells whether a square number matches the description
  445.    desc is of the form b4 or qb4 or just b or 4 */
  446. static
  447. matchpos(desc, squareno, color)
  448.     char *desc;
  449.     int squareno, color;
  450. {
  451.     static char *piececol = "rnbqkbnr";
  452.     char side = FALSE, piece, rownum;
  453.     int row, col;
  454.  
  455.     /* get row and col with player's king on (4,1)    */
  456.     /* (black's board is reflected)            */
  457.     row = 9 - squareno / 10;
  458.     col = squareno % 10;
  459.     if (color == BLACK)
  460.         row = 9 - row;
  461.  
  462.     if (desc [0] == 'k' || desc [0] == 'q') {
  463.         side = desc [0];
  464.         if (!isdigit(desc[1]))
  465.             desc++;
  466.     }
  467.     if (isalpha (desc [0])) {
  468.         piece = desc [0];
  469.         desc++;
  470.     } else
  471.         piece = side;
  472.     if (rownum = isdigit (desc [0]))
  473.         rownum = desc++ [0];
  474.     if (( piece && index(piececol, piece) == NULL)
  475.     || ( rownum && index("12345678", rownum) == NULL)
  476.     || desc [0] != '\0')
  477.         return ILLEGAL;
  478.     else if ((side == 'k' && col <= 4) || (side == 'q' && col >= 5)
  479.     || (rownum && row != rownum - '0')
  480.     || (piece && piececol [col - 1] != piece))
  481.         return FALSE;
  482.     else if (side && !piece && piececol [col - 1] != side)
  483.         return RIGHT_SIDE;   /* eg. b/q-n2 when b is on queen side */
  484.     else
  485.         return RIGHT_FILE;   /* eg. b/q-n2 when b is in queen file */
  486. }
  487.  
  488. static piecetype(letter)
  489.     char letter;
  490. {
  491.     switch (letter) {
  492.     case 'p':
  493.         return PAWN;
  494.     case 'r':
  495.         return ROOK;
  496.     case 'n':
  497.         return KNIGHT;
  498.     case 'b':
  499.         return BISHOP;
  500.     case 'q':
  501.         return QUEEN;
  502.     case 'k':
  503.         return KING;
  504.     default:
  505.         return ILLEGAL_PIECE;
  506.     }
  507. }
  508.  
  509. /*
  510.  * Send the move to the opponent */
  511. send_move(from, to)
  512. {
  513.     fprintf(out, "%1c%1d-%1c%1d\r\n", from%10-1+'a', 9-from/10,
  514.         to%10-1+'a', 9-to/10);
  515. }
  516.